#include "config.h"
#include <boost/format.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <string>
#include "arrow/log.h"

namespace ArrowWebCodeView
{
bool Config::Read(const char* szLocalFolder)
{
    std::string strFilePath = std::string(szLocalFolder) + "/data/web_code_view.json";

    nlohmann::json j;
    try
    {
        std::ifstream fConfig(strFilePath, std::ios_base::in);
        fConfig >> j;
        fConfig.close();
    }
    catch(const std::exception& e)
    {
        ARROW_LOG_ERROR_FMT("read %s fail.error msg %s", strFilePath.c_str(), e.what());
        return false;
    }

    int nTmpMaxSize = 2;
    int nTmpTokenValidity = 24;
    ParesJson(j, m_n32Version, "version");
    ParesJson(j, m_nPort, "port");
    ParesJson(j, m_strDefalutFolder, "defalut_folder");
    ParesJson(j, nTmpTokenValidity, "token_validity");
    ParesJson(j, nTmpMaxSize, "max_file_size");
    ParesJson(j, m_strPassword, "password");
    m_nTokenValidity = nTmpTokenValidity * 3600;
    m_nMaxFileSize = nTmpMaxSize * 1024 * 1024;
    ARROW_LOG_INFO_FMT("Config:\n\tversion:%d \n\tPort:%d \n\tdefault folder:%s \n\ttoken validity:%d \n\tmax file size:%d \n\tpassword:%s",
                       m_n32Version,
                       m_nPort,
                       m_strDefalutFolder.c_str(),
                       m_nTokenValidity,
                       m_nMaxFileSize,
                       m_strPassword.c_str());
    return true;
}

const int32_t& Config::Port() const
{
    return m_nPort;
}

const std::string& Config::DefalutFolder() const
{
    return m_strDefalutFolder;
}

uint32_t Config::TokenValidity()
{
    return m_nTokenValidity;
}

int32_t Config::MaxFileSize() const
{
    return m_nMaxFileSize;
}

std::string Config::Password() const
{
    return m_strPassword;
}

std::string Config::GenerateToken()
{
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    std::string strToken = boost::uuids::to_string(uuid);
    m_mutexMapTokenToTp.lock();
    m_mapTokenToTp[strToken] = std::chrono::steady_clock::now();
    m_mutexMapTokenToTp.unlock();
    return strToken;
}

bool Config::CheckToken(const std::string& strToken)
{
    std::lock_guard<std::mutex> lock(m_mutexMapTokenToTp);
    auto it = m_mapTokenToTp.find(strToken);
    if (it == m_mapTokenToTp.end())
        return false;

    auto now = std::chrono::steady_clock::now();
    if (now - it->second > std::chrono::seconds(AppConfig::Instance()->TokenValidity()))
    {
        m_mapTokenToTp.erase(it);
        return false;
    }

    for (auto it = m_mapTokenToTp.begin(); it != m_mapTokenToTp.end();)
    {
        if (now - it->second > std::chrono::seconds(AppConfig::Instance()->TokenValidity()))
        {
            it = m_mapTokenToTp.erase(it);
        }
        else
        {
            ++it;
        }
    }
    return true;
}

} // namespace ArrowWebSocket